class VkInstanceCpp
{
private:
	VkInstance m_hVkInstance;

	decltype(::vkDestroyInstance) *m_pFn_vkDestroyInstance;

#ifdef PTDEBUG
	decltype(::vkCreateDebugReportCallbackEXT) *m_pFn_vkCreateDebugReportCallbackEXT;
	decltype(::vkDestroyDebugReportCallbackEXT) *m_pFn_vkDestroyDebugReportCallbackEXT;
#endif

	decltype(::vkEnumeratePhysicalDevices) *m_pFn_vkEnumeratePhysicalDevices;
	decltype(::vkGetPhysicalDeviceProperties) *m_pFn_vkGetPhysicalDeviceProperties;
	decltype(::vkGetPhysicalDeviceQueueFamilyProperties) *m_pFn_vkGetPhysicalDeviceQueueFamilyProperties;
	decltype(::vkGetPhysicalDeviceMemoryProperties) *m_pFn_vkGetPhysicalDeviceMemoryProperties;
	decltype(::vkCreateDevice) *m_pFn_vkCreateDevice;

#ifdef VK_KHR_win32_surface
	decltype(::vkCreateWin32SurfaceKHR) *m_pFn_vkCreateWin32SurfaceKHR;
	decltype(::vkGetPhysicalDeviceWin32PresentationSupportKHR) *m_pFn_vkGetPhysicalDeviceWin32PresentationSupportKHR;
#endif

public:
	inline void Construct(VkInstance hVkInstance, decltype(vkGetInstanceProcAddr) *pFn_vkGetInstanceProcAddr)
	{
		m_hVkInstance = hVkInstance;

		m_pFn_vkDestroyInstance = reinterpret_cast<decltype(::vkDestroyInstance) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkDestroyInstance"));

#ifdef PTDEBUG
		m_pFn_vkCreateDebugReportCallbackEXT = reinterpret_cast<decltype(::vkCreateDebugReportCallbackEXT) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkCreateDebugReportCallbackEXT"));
		m_pFn_vkDestroyDebugReportCallbackEXT = reinterpret_cast<decltype(::vkDestroyDebugReportCallbackEXT) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkDestroyDebugReportCallbackEXT"));
#endif

		m_pFn_vkEnumeratePhysicalDevices = reinterpret_cast<decltype(::vkEnumeratePhysicalDevices) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkEnumeratePhysicalDevices"));
		m_pFn_vkGetPhysicalDeviceProperties= reinterpret_cast<decltype(::vkGetPhysicalDeviceProperties) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkGetPhysicalDeviceProperties"));
		m_pFn_vkGetPhysicalDeviceQueueFamilyProperties = reinterpret_cast<decltype(::vkGetPhysicalDeviceQueueFamilyProperties) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkGetPhysicalDeviceQueueFamilyProperties"));
		m_pFn_vkGetPhysicalDeviceMemoryProperties= reinterpret_cast<decltype(::vkGetPhysicalDeviceMemoryProperties) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkGetPhysicalDeviceMemoryProperties"));
		m_pFn_vkCreateDevice = reinterpret_cast<decltype(::vkCreateDevice) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance,"vkCreateDevice"));

#ifdef VK_KHR_win32_surface
		m_pFn_vkCreateWin32SurfaceKHR = reinterpret_cast<decltype(::vkCreateWin32SurfaceKHR) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkCreateWin32SurfaceKHR"));
		m_pFn_vkGetPhysicalDeviceWin32PresentationSupportKHR = reinterpret_cast<decltype(vkGetPhysicalDeviceWin32PresentationSupportKHR) *>(pFn_vkGetInstanceProcAddr(m_hVkInstance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"));
#endif

	}

	inline void DestroyInstance(const VkAllocationCallbacks *pAllocator)
	{
		m_pFn_vkDestroyInstance(m_hVkInstance, pAllocator);
	}

#ifdef PTDEBUG
	inline void CreateDebugReportCallbackEXT(const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback)
	{
		m_pFn_vkCreateDebugReportCallbackEXT(m_hVkInstance, pCreateInfo, pAllocator, pCallback);
	}

	inline void DestroyDebugReportCallbackEXT(VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator)
	{
		m_pFn_vkDestroyDebugReportCallbackEXT(m_hVkInstance, callback, pAllocator);
	}
#endif

	inline VkResult EnumeratePhysicalDevices(uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices)
	{
		return m_pFn_vkEnumeratePhysicalDevices(m_hVkInstance, pPhysicalDeviceCount, pPhysicalDevices);
	}
	
	inline void GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties)
	{
		m_pFn_vkGetPhysicalDeviceProperties(physicalDevice, pProperties);
	}
	
	inline void GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties)
	{
		return m_pFn_vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
	}

	inline void GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties)
	{
		return m_pFn_vkGetPhysicalDeviceMemoryProperties(physicalDevice, pMemoryProperties);
	}
	
	inline VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
	{
		return m_pFn_vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
	}

#ifdef VK_KHR_win32_surface
	inline VkResult CreateWin32SurfaceKHR(const VkWin32SurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface)
	{
		return m_pFn_vkCreateWin32SurfaceKHR(m_hVkInstance, pCreateInfo, pAllocator, pSurface);
	}

	inline VkBool32 GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex)
	{
		return m_pFn_vkGetPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
	}
#endif

};

class VkDeviceCpp
{
private:
	VkDevice m_hVkDevice;

	decltype(::vkDestroyDevice) *m_pFn_vkDestroyDevice;
	decltype(::vkGetDeviceQueue) *m_pFn_vkGetDeviceQueue;
	decltype(::vkQueueSubmit) *m_pFn_vkQueueSubmit;
	decltype(::vkCreateCommandPool) *m_pFn_vkCreateCommandPool;
	decltype(::vkResetCommandPool) *m_pFn_vkResetCommandPool;
	decltype(::vkDestroyCommandPool) *m_pFn_vkDestroyCommandPool;
	decltype(::vkAllocateCommandBuffers) *m_pFn_vkAllocateCommandBuffers;
	decltype(::vkResetCommandBuffer) *m_pFn_vkResetCommandBuffer;
	decltype(::vkFreeCommandBuffers) *m_pFn_vkFreeCommandBuffers;
	decltype(::vkBeginCommandBuffer) *m_pFn_vkBeginCommandBuffer;
	decltype(::vkEndCommandBuffer) *m_pFn_vkEndCommandBuffer;
	decltype(::vkAllocateMemory) *m_pFn_vkAllocateMemory;
	decltype(::vkCreateBuffer) *m_pFn_vkCreateBuffer;
	decltype(::vkDestroyBuffer) *m_pFn_vkDestroyBuffer;
	decltype(::vkGetBufferMemoryRequirements) *m_pFn_vkGetBufferMemoryRequirements;

public:
	inline void Construct(VkDevice hVkDevice, decltype(vkGetDeviceProcAddr) *pFn_vkGetDeviceProcAddr)
	{
		m_hVkDevice = hVkDevice;
		
		m_pFn_vkDestroyDevice= reinterpret_cast<decltype(::vkDestroyDevice) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkDestroyDevice"));
		m_pFn_vkGetDeviceQueue = reinterpret_cast<decltype(::vkGetDeviceQueue) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkGetDeviceQueue"));
		m_pFn_vkQueueSubmit = reinterpret_cast<decltype(::vkQueueSubmit) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkQueueSubmit"));
		m_pFn_vkCreateCommandPool = reinterpret_cast<decltype(::vkCreateCommandPool) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkCreateCommandPool"));
		m_pFn_vkResetCommandPool = reinterpret_cast<decltype(::vkResetCommandPool) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkResetCommandPool"));
		m_pFn_vkDestroyCommandPool = reinterpret_cast<decltype(::vkDestroyCommandPool) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkDestroyCommandPool"));
		m_pFn_vkAllocateCommandBuffers = reinterpret_cast<decltype(::vkAllocateCommandBuffers) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkAllocateCommandBuffers"));
		m_pFn_vkResetCommandBuffer = reinterpret_cast<decltype(::vkResetCommandBuffer) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkResetCommandBuffer"));
		m_pFn_vkFreeCommandBuffers = reinterpret_cast<decltype(::vkFreeCommandBuffers) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkFreeCommandBuffers"));
		m_pFn_vkBeginCommandBuffer = reinterpret_cast<decltype(::vkBeginCommandBuffer) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkBeginCommandBuffer"));
		m_pFn_vkEndCommandBuffer = reinterpret_cast<decltype(::vkEndCommandBuffer) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkEndCommandBuffer"));
		m_pFn_vkAllocateMemory = reinterpret_cast<decltype(::vkAllocateMemory) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkAllocateMemory"));
		m_pFn_vkCreateBuffer = reinterpret_cast<decltype(::vkCreateBuffer) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkCreateBuffer"));
		m_pFn_vkDestroyBuffer = reinterpret_cast<decltype(::vkDestroyBuffer) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkDestroyBuffer"));
		m_pFn_vkGetBufferMemoryRequirements = reinterpret_cast<decltype(::vkGetBufferMemoryRequirements) *>(pFn_vkGetDeviceProcAddr(m_hVkDevice, "vkGetBufferMemoryRequirements"));
	}

	inline void DestroyDevice(const VkAllocationCallbacks *pAllocator)
	{
		return m_pFn_vkDestroyDevice(m_hVkDevice, pAllocator);
	}

	inline void GetDeviceQueue(uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue)
	{
		return m_pFn_vkGetDeviceQueue(m_hVkDevice, queueFamilyIndex, queueIndex, pQueue);
	}

	inline VkResult QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence)
	{
		return m_pFn_vkQueueSubmit(queue, submitCount, pSubmits, fence);
	}

	inline VkResult CreateCommandPool(const VkCommandPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool)
	{
		return m_pFn_vkCreateCommandPool(m_hVkDevice, pCreateInfo, pAllocator, pCommandPool);
	}

	inline VkResult ResetCommandPool(VkCommandPool commandPool, VkCommandPoolResetFlags flags)
	{
		return m_pFn_vkResetCommandPool(m_hVkDevice, commandPool, flags);
	}

	inline void DestroyCommandPool(VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator)
	{
		return m_pFn_vkDestroyCommandPool(m_hVkDevice, commandPool, pAllocator);
	}

	inline VkResult AllocateCommandBuffers(const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers)
	{
		return m_pFn_vkAllocateCommandBuffers(m_hVkDevice, pAllocateInfo, pCommandBuffers);
	}

	inline VkResult ResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags)
	{
		return m_pFn_vkResetCommandBuffer(commandBuffer, flags);
	}

	inline void FreeCommandBuffers(VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers)
	{
		return m_pFn_vkFreeCommandBuffers(m_hVkDevice, commandPool, commandBufferCount, pCommandBuffers);
	}

	inline VkResult BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo)
	{
		return m_pFn_vkBeginCommandBuffer(commandBuffer, pBeginInfo);
	}

	inline VkResult EndCommandBuffer(VkCommandBuffer commandBuffer)
	{
		return m_pFn_vkEndCommandBuffer(commandBuffer);
	}

	inline VkResult AllocateMemory(const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory)
	{
		return m_pFn_vkAllocateMemory(m_hVkDevice, pAllocateInfo, pAllocator, pMemory);
	}

	inline VkResult CreateBuffer(const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer)
	{
		return m_pFn_vkCreateBuffer(m_hVkDevice, pCreateInfo, pAllocator, pBuffer);
	}

	inline void DestroyBuffer(VkBuffer buffer, const VkAllocationCallbacks *pAllocator)
	{
		return m_pFn_vkDestroyBuffer(m_hVkDevice, buffer, pAllocator);
	}

	inline void GetBufferMemoryRequirements(VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements)
	{
		return m_pFn_vkGetBufferMemoryRequirements(m_hVkDevice, buffer, pMemoryRequirements);
	}

};